9-1 @k

所謂「一維內插」(1-D Interpolation),就是根據一組已知的資料點(包含輸入及輸出,其中輸入是一維資料,輸出也是一維資料),來建立一個連續的函數,以便計算任意輸入資料點所對應的輸出值。一維內插的方法很多,MATLAB 提供了兩種基本方法:

本節將對這兩種方法來進行說明。

MATLAB 最常用的一維內插指令是 interp1,其原理是利用多項式來進行內插運算。interp1 的使用語法為

yi = interp1(x, y, xi, method)

其中向量 x 是資料點的 x 座標(輸入值),向量 y 是資料點的 y 座標(輸出值),向量 xi 是內插點(輸入值,未知其對應輸出值),字串 method 則指定使用的內插方法,共有六種:

在下列範例中,我們使用上述方法中的前四種來對一維資料進行內插:

Example 1: 09-內插法/interp101.mx = 0:1:4*pi; y = sin(x).*exp(-x/5); xi = 0:0.1:4*pi; y1 = interp1(x, y, xi, 'nearest'); y2 = interp1(x, y, xi, 'linear'); y3 = interp1(x, y, xi, 'pchip'); y4 = interp1(x, y, xi, 'spline'); plot(x, y, 'o', xi, y1, xi, y2, xi, y3, xi, y4); legend('Original', 'Nearest', 'Linear', 'Pchip', 'Spline');

由上圖可看出,Spline 和 Cubic 所產生的曲線較平滑,但它們所需的計算時間也較久。以上這四種內插法的比較表如下:

  Nearest Linear Cubic Cubic Spline
執行時間 1(短) 2 3 4(長)
曲線平滑度 1(差) 2 3 4(好)
記憶體使用量 1(少) 2 4(多) 3

在使用 interp1 時,向量 x 必須是嚴格遞增或遞減,但元素之間不必是等間隔。此外,xi 的範圍也必須落在 x 的範圍之內,才能進行內插的運算。

Hint
如果 xi 的範圍在 x 的範圍之外,那麼我們可以使用 yi = interp1(x, y, xi, method, ‘extrap’) 的方式來進行外插(Extrapolation),以求得在範圍外的 xi 元素所對應的 yi 值。

在上述範例的圖形,可能不容易看出每一種方法的效果,筆者特別另外寫了一個程式,可以讓使用者拖放取樣點,內插曲線就會跟著改變,檔案名稱是 interpAnim01.m,執行後的圖形如下:

使用者可以在上述圖形視窗中,拖放每一個取樣點,就可以立刻看到內插曲線的變化,也同時可以知道各種內插方法的特性。

除了 interp1 之外,另一個較少用的 MATLAB 的指令 interpft 可進行基於 FFT(Fast Fourier Transform,快速傅立葉轉換)的內插法。此方法先計算資料點的傅立葉轉換,再用更密集的內插點來進行反傅立葉轉換。interft 的使用語法為

y = interpft(yi, n)

其中向量 yi 是一個經由等距取點的函數值,n 則是等距取點的內插點數。例如:

Example 2: 09-內插法/interpft01.mn = 11; % Number of the original data points factor = 4; % Increase the data by this factor x = linspace(0, 2*pi, n); y = sin(x).*exp(-x/5); xi = (0:factor*n-1)*(x(2)-x(1))/factor; yi = interpft(y, factor*n); plot(x, y, 'ro', xi, yi, '.-'); legend('Original', 'Curve by interpft');

Hint
一般而言,內插曲線必須通過每一個已知的取樣點,而迴歸曲線則不需要通過取樣點。因此,內插法適用於雜訊很少的取樣資料。(有關曲線擬合或迴歸分析,請參閱本書「曲線擬合與迴歸分析」的相關章節。)

如果我們要根據平面上的有限資料點,來描繪初一個物體的外型,也可以使用一維內插,但是此時內插資料點會變成兩組,分別是

在下列範例中,我們共有七個資料點,散佈在二度空間,我們可以使用 interp1 的 spline 方法,來畫出連續平滑的圖形,如下:

Example 3: 09-內插法/interp102.mx = [0 2 4 3 1 2 1]; y = [4 1 2 4 5 2 0]; index = 1:length(x); index2 = linspace(1, length(x), 101); x2 = interp1(index, x, index2, 'spline'); y2 = interp1(index, y, index2, 'spline'); plot(x, y, 'o', x2, y2, '-'); legend('Origianl data', 'Interpolated data');

在上述範例中,原有的資料只有七點,但是使用一維內插,我們就可以產生平滑連續的圖形,這也是在電腦圖學(Computer Graphics)最常見的做法,也就是以少數控制點(Control Points)來代表一個物件,然後再使用內插來產生整個物件的細緻圖形。

當然,如果我們選用不同的方法,得到的平滑效果也會不同,下列範例使用 interp1 的四種方法,來對上一個範例的資料點進行內插,如下:

Example 4: 09-內插法/interp103.mx = [0 2 4 3 1 2 1]; y = [4 1 2 4 5 2 0]; index = 1:length(x); index2 = linspace(1, length(x), 101); x2 = interp1(index, x, index2, 'nearest'); y2 = interp1(index, y, index2, 'nearest'); x3 = interp1(index, x, index2, 'linear'); y3 = interp1(index, y, index2, 'linear'); x4 = interp1(index, x, index2, 'pchip'); y4 = interp1(index, y, index2, 'pchip'); x5 = interp1(index, x, index2, 'spline'); y5 = interp1(index, y, index2, 'spline'); plot(x, y, 'o', x2, y2, '-'); plot(x, y , 'o', x2 ,y2, x3 ,y3 ,x4 ,y4, x5, y5); legend('Original', 'Nearest', 'Linear', 'Pchip', 'Spline');

同樣地,在上述範例的圖形,可能不容易看出每一種方法的效果,筆者特別另外寫了一個程式,可以讓使用者拖放取樣點,內插曲線就會跟著改變,檔案名稱是 interpAnim02.m,執行後的圖形如下:

這個展示程式很有趣,請讀者務必自己試看看,拖放幾個控制點,看看會產生什麼不同效果的內插曲線。


MATLAB程式設計:進階篇